package cn.chiship.bs.api.biz.service.impl;


import cn.chiship.bs.api.biz.service.BaseService;
import cn.chiship.bs.api.core.config.properties.GlobalProperties;
import cn.chiship.bs.api.core.util.ExportUtil;
import cn.chiship.sdk.core.base.BaseResult;
import cn.chiship.sdk.core.base.ProgressResult;
import cn.chiship.sdk.core.enums.BaseResultEnum;
import cn.chiship.sdk.core.base.constants.BaseConstants;
import cn.chiship.sdk.core.enums.ProgressResultEnum;
import cn.chiship.sdk.core.exception.custom.SystemErrorException;
import cn.chiship.sdk.core.id.SnowflakeIdUtil;
import cn.chiship.sdk.core.util.CamelCaseUtils;
import cn.chiship.sdk.core.util.OutUtil;
import cn.chiship.sdk.core.util.RandomUtil;
import cn.chiship.sdk.core.util.StringUtil;
import cn.chiship.bs.api.biz.mapper.BaseMapper;
import cn.chiship.bs.api.biz.pojo.vo.PageVo;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;

import javax.servlet.http.HttpServletResponse;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author lijian
 */
public abstract class BaseServiceImpl<Record, Example> implements BaseService<Record, Example> {

    @Autowired
    private BaseMapper<Record, Example> baseMapper;
    @Autowired
    private GlobalProperties globalProperties;

    /**
     * 全局所有进度
     */
    public ConcurrentHashMap<String, ProgressResult> processStatusHm;

    public BaseServiceImpl() {
        processStatusHm = new ConcurrentHashMap<>();
    }

    @Override
    public BaseResult insertSelective(Record record) {
        try {
            /**
             * 赋初始值
             */
            Class<?> clazz = record.getClass();
            Field id = clazz.getDeclaredField("id");
            Field gmtCreated = clazz.getDeclaredField("gmtCreated");
            Field gmtModified = clazz.getDeclaredField("gmtModified");
            Field isDeleted = clazz.getDeclaredField("isDeleted");
            gmtCreated.setAccessible(true);
            gmtModified.setAccessible(true);
            isDeleted.setAccessible(true);
            id.setAccessible(true);

            /**
             * id 为空,根据用户配置的生成原则进行生产
             * 1.若主键类型为Long类型则自动使用雪花算法生成主键  2.若主键类型为String类型，则根据配置使用对应的生成原则  3.若业务层已经对主键赋值了，则忽略此配置
             * UUID         默认调用  @see cn.chiship.sdk.core.util.RandomUtil.uuidLowerCase() 方法
             * SNOWFLAKE    雪花算法 默认调用  see cn.chiship.sdk.core.id.generateId() 方法
             */
            String getId = "getId";
            String longs = "Long";
            String uuid = "UUID";
            String snowflake = "SNOWFLAKE";
            if (StringUtil.isNull(clazz.getMethod(getId).invoke(record))) {
                if (longs.equals(id.getType().getSimpleName())) {
                    id.set(record, SnowflakeIdUtil.generateId());
                } else {
                    String tableKeyGenerator = globalProperties.getKeyGenerator();
                    if (uuid.equals(tableKeyGenerator)) {
                        id.set(record, RandomUtil.uuidLowerCase());
                    }
                    if (snowflake.equals(tableKeyGenerator)) {
                        id.set(record, SnowflakeIdUtil.generateStrId());
                    }
                }
            }

            gmtCreated.set(record, System.currentTimeMillis());
            gmtModified.set(record, System.currentTimeMillis());
            isDeleted.set(record, BaseConstants.NO);


            boolean flag = baseMapper.insertSelective(record) > 0 ? true : false;
            if (!flag) {
                return new BaseResult(Boolean.FALSE, BaseResultEnum.EXCEPTION_DATA_BASE_INSERT, null);
            } else {
                return new BaseResult(Boolean.TRUE, BaseResultEnum.SUCCESS, record);
            }
        } catch (Exception e) {
            throw new SystemErrorException(e.getCause());
        }
    }

    @Override
    public BaseResult deleteByExample(Example example) {
        try {
            baseMapper.deleteByExample(example);
            return new BaseResult(Boolean.TRUE, BaseResultEnum.SUCCESS, null);
        } catch (Exception e) {
            throw new SystemErrorException(e.getCause());
        }
    }

    @Override
    public BaseResult deleteByPrimaryKey(Object id) {
        try {
            baseMapper.deleteByPrimaryKey(id);
            return new BaseResult(Boolean.TRUE, BaseResultEnum.SUCCESS, null);
        } catch (Exception e) {
            throw new SystemErrorException(e.getCause());
        }
    }

    @Override
    public BaseResult updateByExampleSelective(Record record, Example example) {
        try {
            /**
             * 赋初始值
             */
            Class<?> clazz = record.getClass();
            Field gmtModified = clazz.getDeclaredField("gmtModified");
            gmtModified.setAccessible(true);
            gmtModified.set(record, System.currentTimeMillis());

            boolean flag = baseMapper.updateByExampleSelective(record, example) > 0 ? true : false;
            if (!flag) {
                return new BaseResult(Boolean.FALSE, BaseResultEnum.EXCEPTION_DATA_BASE_UPDATE, null);
            } else {
                return new BaseResult(Boolean.TRUE, BaseResultEnum.SUCCESS, record);
            }
        } catch (Exception e) {
            throw new SystemErrorException(e.getCause());
        }
    }

    @Override
    public BaseResult updateByPrimaryKeySelective(Record record) {
        try {
            /**
             * 赋初始值
             */
            Class<?> clazz = record.getClass();
            Field gmtModified = clazz.getDeclaredField("gmtModified");
            gmtModified.setAccessible(true);
            gmtModified.set(record, System.currentTimeMillis());
            boolean flag = baseMapper.updateByPrimaryKeySelective(record) > 0 ? true : false;
            if (!flag) {
                return new BaseResult(Boolean.FALSE, BaseResultEnum.EXCEPTION_DATA_BASE_UPDATE, null);
            } else {
                return new BaseResult(Boolean.TRUE, BaseResultEnum.SUCCESS, record);
            }
        } catch (Exception e) {
            throw new SystemErrorException(e.getCause());
        }

    }

    @Override
    public List<Record> selectByExample(Example example) {
        List<Record> records = baseMapper.selectByExample(example);
        return records;
    }


    @Override
    public Record selectByPrimaryKey(Object id) {
        Record record = baseMapper.selectByPrimaryKey(id);
        return record;
    }

    @Override
    public BaseResult selectDetailsByPrimaryKey(Object id) {
        return BaseResult.error("请在【" + this.getClass().getSimpleName() + "】类中对方法【selectDetailsByPrimaryKey】重写,进行业务配置");
    }

    @Override
    public long countByExample(Example example) {
        return baseMapper.countByExample(example);
    }


    @Override
    public PageVo selectPageByExample(PageVo pageVo, Example example, String sort) {
        Page page = PageHelper.startPage(pageVo.getCurrent().intValue(), pageVo.getSize().intValue());
        StringBuilder buffer = new StringBuilder();
        if (sort != null) {
            String a = ",";
            for (String s : sort.split(a)) {
                if ("+".equals(sort.substring(0, 1))) {
                    buffer.append(CamelCaseUtils.toUnderlineName(s.substring(1)) + " ASC");
                } else {
                    buffer.append(CamelCaseUtils.toUnderlineName(s.substring(1)) + " DESC");
                }
                buffer.append(",");
            }
        }
        if (buffer.length() > 0) {
            sort = buffer.substring(0, buffer.length() - 1);
        }
        PageHelper.orderBy(sort);
        List<Record> records = baseMapper.selectByExample(example);
        pageVo.setRecords(records);
        pageVo.setTotal(page.getTotal());
        pageVo.setPages(Long.valueOf(page.getPages()));
        return pageVo;
    }


    @Override
    public void exportData(HttpServletResponse response, Map<String, Object> paramMap) throws Exception {
        OutUtil.writeJson(response, BaseResult.error("请在【" + this.getClass().getSimpleName() + "】类中对方法【exportData】重写,进行业务配置"));
    }

    @Override
    @Async
    public void asyncExportData(HttpServletResponse response, String taskId, Map<String, Object> paramMap) {
        try {
            /**
             * 以下代码均为举例说明
             * 具体业务具体写
             */
            processStatusHm.put(taskId, ProgressResult.out(ProgressResultEnum.PROGRESS_PROGRESS_ENUM, "40%"));
            Thread.sleep(3000);
            processStatusHm.put(taskId, ProgressResult.out(ProgressResultEnum.PROGRESS_ERROR_ENUM, "请在【" + this.getClass().getSimpleName() + "】类中对方法【asyncExportData】重写,进行业务配置"));
        } catch (Exception e) {
            processStatusHm.put(taskId, ProgressResult.out(ProgressResultEnum.PROGRESS_ERROR_ENUM, e.getLocalizedMessage()));
        }
    }

    @Override
    public void getExportProcessStatus(HttpServletResponse response, String taskId) throws Exception {
        ProgressResult progressResult = processStatusHm.get(taskId);
        if (StringUtil.isNull(progressResult)) {
            OutUtil.writeJson(response, BaseResult.error("你开启了异步导出，确定调用【" + this.getClass().getSimpleName() + "】类中对方法【asyncExportData】了吗?"));

        } else {
            if (progressResult.isFile()) {
                byte[] bytes = progressResult.getBytes();
                if (StringUtil.isNull(bytes)) {
                    processStatusHm.put(taskId, ProgressResult.out(ProgressResultEnum.PROGRESS_ERROR_ENUM, "标题列数与数值列数不匹配或不支持的导出格式！"));
                } else {
                    System.out.println("------------processStatusHM:" + processStatusHm.size());

                    processStatusHm.put(taskId, ProgressResult.out(ProgressResultEnum.PROGRESS_FINISH_ENUM));
                    System.out.println("文件大小:" + bytes.length);
                    ExportUtil.getInstance().exportByType(response,
                            progressResult.getExportType(),
                            progressResult.getFileName(),
                            bytes
                    );
                    Thread.sleep(2000);
                    processStatusHm.remove(taskId);
                }

            } else {
                OutUtil.writeJson(response, BaseResult.ok(progressResult));
            }
        }

    }

    @Override
    public void asyncImportData(InputStream inputStream, String taskId, Map<String, Object> paramMap) {
        try {
            /**
             * 以下代码均为举例说明
             * 具体业务具体写
             */
            processStatusHm.put(taskId, ProgressResult.out(ProgressResultEnum.PROGRESS_PROGRESS_ENUM, "40%"));
            Thread.sleep(3000);
            processStatusHm.put(taskId, ProgressResult.out(ProgressResultEnum.PROGRESS_ERROR_ENUM, "请在【" + this.getClass().getSimpleName() + "】类中对方法【asyncImportData】重写,进行业务配置"));
        } catch (Exception e) {
            processStatusHm.put(taskId, ProgressResult.out(ProgressResultEnum.PROGRESS_ERROR_ENUM, e.getLocalizedMessage()));
        }
    }

    @Override
    public BaseResult getImportProcessStatus(String taskId) {
        ProgressResult progressResult = processStatusHm.get(taskId);
        if (StringUtil.isNull(progressResult)) {
            return BaseResult.error("你开启了异步导入，确定调用【" + this.getClass().getSimpleName() + "】类中对方法【asyncExportData】了吗?");

        }
        return BaseResult.ok(progressResult);
    }

    @Override
    public BaseResult validateExistByField(String id, String field, String value) {
        /**
         * 以下代码均为举例说明
         */
        /*
        Example example=new **Example();
        Example.Criteria criteria=example.createCriteria();
        if (!StringUtil.isNullOrEmpty(id)){
            criteria.andIdNotEqualTo(id);
        }
        switch (field){
            case "userName":
                criteria.andUserNameEqualTo(value);
                break;
            case "userCode":
                criteria.andUserCodeEqualTo(value);
                break;
            case "mobile":
                criteria.andMobileEqualTo(value);
                break;
            default:
                flag=false;
        }
        if (flag){
            return BaseResult.ok(**Mapper.countByExample(example)>0);
        }else{
            return BaseResult.error(BaseResultEnum.FAILED,"暂未配置对字段"+field+"的校验");
        }*/
        return BaseResult.error("请在【" + this.getClass().getSimpleName() + "】类中对方法【validateExistByField】重写,进行业务配置");
    }
}
